'use strict'

import { app, BrowserWindow, ipcMain, Menu } from 'electron'
import * as async from 'async'
import { getBookChapter, formatError, getNovelChapter, genMobi, genEpub } from './service'
import { db, novel } from 'novel-parser'
import * as fs from 'fs'
import * as log from 'electron-log'
import { CALLBACK,
  CACHE_CHAPTER_LIST,
  GEN_MOBI,
  GEN_EPUB,
  SEARCH_NOVEL,
  STOP_SEARCH_NOVEL
} from 'novel-parser/servies/channel'

/**
 * Set `__static` path to static files in production
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
 */
if (process.env.NODE_ENV !== 'development') {
  global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}

db.setBasePath(process.env.NODE_ENV === 'development' ? __dirname : app.getPath('userData'))

let mainWindow
const winURL = process.env.NODE_ENV === 'development'
  ? `http://localhost:9080`
  : `file://${__dirname}/index.html`

function createWindow () {
  /**
   * Initial window options
   */
  mainWindow = new BrowserWindow({
    height: 563,
    useContentSize: true,
    width: 1000,
    webPreferences: {
      nodeIntegration: true
    }
  })

  mainWindow.loadURL(winURL)

  mainWindow.on('closed', () => {
    mainWindow = null
  })
}

const createMenu = () => {
  const application = {
    label: 'Application',
    submenu: [
      {
        label: 'About Application',
        role: 'about'
      },
      {
        type: 'separator'
      },
      {
        label: 'Quit',
        accelerator: 'Command+Q',
        click: () => {
          app.quit()
        }
      }
    ]
  }

  const edit = {
    label: 'Edit',
    submenu: [
      {
        label: 'Undo',
        accelerator: 'CmdOrCtrl+Z',
        role: 'undo'
      },
      {
        label: 'Redo',
        accelerator: 'Shift+CmdOrCtrl+Z',
        role: 'redo'
      },
      {
        type: 'separator'
      },
      {
        label: 'Cut',
        accelerator: 'CmdOrCtrl+X',
        role: 'cut'
      },
      {
        label: 'Copy',
        accelerator: 'CmdOrCtrl+C',
        role: 'copy'
      },
      {
        label: 'Paste',
        accelerator: 'CmdOrCtrl+V',
        role: 'paste'
      },
      {
        label: 'Select All',
        accelerator: 'CmdOrCtrl+A',
        role: 'selectAll'
      }
    ]
  }

  const template = [application, edit]

  Menu.setApplicationMenu(Menu.buildFromTemplate(template))
}

app.on('ready', () => {
  createWindow()
  createMenu()
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow()
  }
})

require('./autoStart')

ipcMain.on(CACHE_CHAPTER_LIST, async (event, arg) => {
  const { novelId, force } = arg
  const result = await db.novels.findOne({ _id: novelId })
  const chapters = result.chapters.filter(chapter => {
    return force || !fs.existsSync(getBookChapter(result._id, chapter.chapterUrl))
  })
  async.mapLimit(chapters, 5, (item, callback) => {
    getNovelChapter(result, item.chapterUrl, force).then(() => {
      mainWindow.webContents.send(CACHE_CHAPTER_LIST + CALLBACK, { code: 200, data: { status: 'item-done', item } })
      callback()
    }).catch(e => {
      callback(e)
    })
  }, (err) => {
    log.error(err)
    if (err) {
      event.sender.send(CACHE_CHAPTER_LIST + CALLBACK, formatError(err))
    } else {
      event.sender.send(CACHE_CHAPTER_LIST + CALLBACK, { code: 200, data: { status: 'done' } })
    }
  })
})

ipcMain.on(GEN_MOBI, async (event, arg) => {
  genMobi(arg, mainWindow).then(res => {
    event.sender.send(GEN_MOBI + CALLBACK, { code: 200, data: res })
  }).catch(e => {
    event.sender.send(GEN_MOBI + CALLBACK, formatError(e))
  })
})

ipcMain.on(GEN_EPUB, async (event, arg) => {
  console.log(GEN_EPUB)
  genEpub(arg, mainWindow).then(res => {
    event.sender.send(GEN_EPUB + CALLBACK, { code: 200, data: res })
  }).catch(e => {
    console.log(e)
    event.sender.send(GEN_EPUB + CALLBACK, formatError(e))
  })
})

let stop = false

ipcMain.on(SEARCH_NOVEL, async (event, arg) => {
  const { searchKey } = arg
  const sources = await db.sources.find()

  const iter = sources[Symbol.iterator]()
  let count = 0
  let next = { done: true }
  stop = false
  let fn = () => {
    if (count < 5) {
      next = iter.next()
      if (next.value) {
        console.log('start search ' + searchKey, next.value)
        const source = next.value
        novel[SEARCH_NOVEL](source, searchKey)
          .then(result => mainWindow.webContents.send(SEARCH_NOVEL + CALLBACK, { code: 200, data: { result, source } }))
          .catch(e => mainWindow.webContents.send(SEARCH_NOVEL + CALLBACK, formatError(e, source)))
          .finally(() => count--)
        count++
      }
    }
    console.log(count)
    if (!next.done || !stop) {
      console.log(2)
      setTimeout(() => {
        fn()
      }, 1000)
    }
  }
  setTimeout(() => {
    fn()
  }, 0)
})

ipcMain.on(STOP_SEARCH_NOVEL, (event) => {
  stop = true
  event.sender.send(STOP_SEARCH_NOVEL + CALLBACK, {
    code: 200
  })
})

/**
 * Auto Updater
 *
 * Uncomment the following code below and install `electron-updater` to
 * support auto updating. Code Signing with a valid certificate is required.
 * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
 */

/*
import { autoUpdater } from 'electron-updater'

autoUpdater.on('update-downloaded', () => {
  autoUpdater.quitAndInstall()
})

app.on('ready', () => {
  if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
 */
